home *** CD-ROM | disk | FTP | other *** search
/ Delphi Developer's Kit 1996 / Delphi Developer's Kit 1996.iso / power / gif2bmpa / code / webpaper / gif2bmp.pas
Encoding:
Pascal/Delphi Source File  |  1995-12-22  |  26.5 KB  |  789 lines

  1. unit Gif2Bmp;
  2.  Gif to Bmp a free gif to Bmp conversion routine.
  3.  Converted to Delphin Pascal by Richard Dominelli May 1995
  4.  
  5.  Change this code anyway you would like it is free.  Version 2.0 is in
  6.  the works which will use an assembly lzw decoder.  Any suggested
  7.  improvements are very welcome.  
  8.                                    
  9.  Any comments or questions please write me at one of the following addresses.
  10.  
  11.  RichardA_Dominelli@mskcc.org
  12.  dopey@felix.mskcc.org
  13.  73541,2555 on Compuserve. 
  14.  
  15.  I Hope you find this usefull.
  16.  
  17.  Rich
  18.  
  19.  Gif2Bmp was based on and would not have been possible without...
  20.  
  21.  GifUtl .pas - (c)Copyright 1993 Sean Wenzel
  22.  
  23.  Sean Writes : 
  24.     Users are given the right to use/modify and distribute this source code as
  25.     long as credit is given where due.  I would also ask that anyone who makes
  26.     use of this source/program drop me a line at my CompuServe address of
  27.     71736,1245.  Just curious...
  28.  
  29. Revision History
  30.  
  31. Version        date        Comment
  32. 1.1            6/1/1995    Added better error handling and exceptions for conditions
  33.                         which previously caused GPF's
  34.  
  35. 1.2            7/31/1995    Fix pallete problem on 256 color gifs.  Windows
  36.                         Bitmaps are stored with 4 bytes per pallet entry. 4th
  37.                         byte is ignored.
  38.  
  39.  
  40.  
  41. }
  42.  
  43.  
  44. {$R-}   {       range checking off }  { Put them on if you like but it slows down the}
  45. {$S-} { stack checking off }  { decoding  (almost doubles it!) }
  46. {$I-} { i/o checking off }
  47.  
  48. interface
  49.  
  50. uses WinTypes,Forms,ExtCtrls,SysUtils,Classes,Gauges;
  51.  
  52. {===============================================================
  53.    Gif Records and Structs
  54. ===============================================================}
  55.    
  56. type
  57.     TDataSubBlock = record
  58.         Size: byte;     { size of the block -- 0 to 255 }
  59.         Data: array[1..255] of byte; { the data }
  60.     end;
  61.  
  62. const
  63.     BlockTerminator: byte = 0; { terminates stream of data blocks }
  64.  
  65. type
  66.     THeader = record
  67.         Signature: array[0..2] of char; { contains 'GIF' }
  68.         Version: array[0..2] of char;   { '87a' or '89a' }
  69.     end;
  70.  
  71.     TLogicalScreenDescriptor = record
  72.         ScreenWidth: word;              { logical screen width }
  73.         ScreenHeight: word;  { logical screen height }
  74.         PackedFields: byte;     { packed fields - see below }
  75.         BackGroundColorIndex: byte;     { index to global color table }
  76.         AspectRatio: byte;      { actual ratio = (AspectRatio + 15) / 64 }
  77.     end;
  78.  
  79. const
  80. { logical screen descriptor packed field masks }
  81.     lsdGlobalColorTable = $80;  { set if global color table follows L.S.D. }
  82.     lsdColorResolution = $70;               { Color resolution - 3 bits }
  83.     lsdSort = $08;                                                  { set if global color table is sorted - 1 bit }
  84.     lsdColorTableSize = $07;                { size of global color table - 3 bits }
  85.                                                             { Actual size = 2^value+1    - value is 3 bits }
  86.  
  87. type
  88.     TColorItem = record     { one item a a color table }
  89.         Red: byte;
  90.         Green: byte;
  91.         Blue: byte;
  92.     end;
  93.  
  94.     TColorTable = array[0..255] of TColorItem;      { the color table }
  95.  
  96. const
  97.     ImageSeperator: byte = $2C;
  98.  
  99. type
  100.     TImageDescriptor = record
  101.         Seperator: byte;                         { fixed value of ImageSeperator }
  102.         ImageLeftPos: word; {Column in pixels in respect to left edge of logical screen }
  103.         ImageTopPos: word;{row in pixels in respect to top of logical screen }
  104.         ImageWidth: word;       { width of image in pixels }
  105.         ImageHeight: word;      { height of image in pixels }
  106.         PackedFields: byte; { see below }
  107.     end;
  108. const
  109.     { image descriptor bit masks }
  110.         idLocalColorTable = $80; { set if a local color table follows }
  111.         idInterlaced = $40;                      { set if image is interlaced }
  112.         idSort = $20;                                            { set if color table is sorted }
  113.         idReserved = $0C;                                { reserved - must be set to $00 }
  114.         idColorTableSize = $07;  { size of color table as above }
  115.  
  116.     Trailer: byte = $3B;    { indicates the end of the GIF data stream }
  117.  
  118. { other extension blocks not currently supported by this unit
  119.     - Graphic Control extension
  120.     - Comment extension           I'm not sure what will happen if these blocks
  121.     - Plain text extension        are encountered but it'll be interesting
  122.     - application extension }
  123.  
  124. const
  125.     ExtensionIntroducer: byte = $21;
  126.     MAXSCREENWIDTH = 800;
  127.  
  128. type
  129.     TExtensionBlock = record
  130.         Introducer: byte;                               { fixed value of ExtensionIntroducer }
  131.         ExtensionLabel: byte;
  132.         BlockSize: byte;
  133.     end;
  134.  
  135.     PCodeItem = ^TCodeItem;
  136.     TCodeItem = record
  137.         Code1, Code2: byte;
  138.     end;
  139. {===============================================================}
  140. {    Bitmap File Structs                                                                  
  141. {===============================================================}
  142.  
  143. type
  144.    GraphicLine = array [0..2048] of byte;
  145.    PBmLine = ^TBmpLinesStruct;
  146.     TBmpLinesStruct = record
  147.         LineData : GraphicLine;
  148.         LineNo : LongInt;
  149.     end;
  150. {===============================================================}
  151.  
  152.  
  153.  
  154.  
  155. const
  156.     MAXCODES = 4095;        { the maximum number of different codes 0 inclusive }
  157.  
  158.  
  159.  
  160. type
  161.     { This is the actual gif object }
  162.     PGif = ^TGif;
  163.     TGif = class(TObject)
  164.         Stream: TMemoryStream;{PBufStream;}  { the file stream for the gif file }
  165.         Header: THeader;               { gif file header }
  166.         LogicalScreen: TLogicalScreenDescriptor;  { gif screen descriptor }
  167.         GlobalColorTable: TColorTable;            { global color table }
  168.         LocalColorTable: TColorTable;             { local color table }
  169.         ImageDescriptor: TImageDescriptor;        { image descriptor }
  170.         UseLocalColors: boolean;                  { true if local colors in use }
  171.         Interlaced: boolean;                                    { true if image is interlaced }
  172.         LZWCodeSize: byte;                                       { minimum size of the LZW codes in bits }
  173.         ImageData: TDataSubBlock;                { variable to store incoming gif data }
  174.         TableSize: word;                                                 { number of entrys in the color table }
  175.         BitsLeft, BytesLeft: integer;{ bits left in byte - bytes left in block }
  176.         BadCodeCount: word;          { bad code counter }
  177.         CurrCodeSize: integer;       { Current size of code in bits }
  178.         ClearCode: integer;          { Clear code value }
  179.         EndingCode: integer;         { ending code value }
  180.         Slot: word;                                     { position that the next new code is to be added }
  181.         TopSlot: word;      { highest slot position for the current code size }
  182.         HighCode: word;     { highest code that does not require decoding }
  183.         NextByte: integer;      { the index to the next byte in the datablock array }
  184.         CurrByte: byte;                 { the current byte }
  185.         DecodeStack: array[0..MAXCODES] of byte; { stack for the decoded codes }
  186.         Prefix: array[0..MAXCODES] of word;                     { array for code prefixes }
  187.         Suffix: array[0..MAXCODES] of byte;             { array for code suffixes }
  188.         LineBuffer: GraphicLine; { array for buffer line output }
  189.         CurrentX, CurrentY: integer;                                            { current screen locations }
  190.         Status: word;             
  191.         InterlacePass: byte;    { interlace pass number }
  192.         {Conversion Routine Vars}
  193.         Gauge : TGauge;
  194.         Stat  : TPanel;                              { status of the decode }
  195.         ProgFlag : boolean;
  196.         BmHeader : TBitmapInfoHeader; {File Header for bitmap file}
  197.         ImageLines : TList; {Image data} 
  198.         {Member Functions}
  199.         constructor Create;
  200.         destructor Destroy; virtual;
  201.  
  202.         procedure SetIndicators(MyGauge :TGauge; MyStat : TPanel); {On going status indicators}
  203.         procedure WriteBitmap(ABMPName:string); {Writes out the header info
  204.                                            writes out the pallet in correct order. 
  205.                                            Arranges the lines in correct order.
  206.                                            Writes out the image lines in correct order}
  207.  
  208.         procedure Error(What: integer);
  209.         procedure InitCompressionStream;        { initializes info for decode }
  210.         procedure ReadSubBlock;                          { reads a data subblock from the stream }
  211.         procedure Decode(Beep: boolean);        { the actual LZW decoding routine }
  212.         procedure CreateLine;
  213.  
  214.         function Convert(AGifName,ABmpName:string):integer; {Converts gif file to bmp file}
  215.         function GifConvert(ABmpName:string):integer; {Converts gif to bmp}
  216.         function CreateBitHeader:integer; {Takes the gif header information and converts it to BMP}
  217.  
  218.         function ConvertfromMem(AMemStream:TMemoryStream;ABmpName:string):integer;
  219.         function ParseMem:integer;
  220.         function NextCode: word;                                        { returns the next available code }
  221.     end;
  222.  
  223.  
  224. const
  225. { error constants }
  226.     geNoError = 0;                          { no errors found }
  227.     geNoFile = 1;         { gif file not found }
  228.     geNotGIF = 2;         { file is not a gif file }
  229.     geNoGlobalColor = 3;  { no Global Color table found }
  230.     geImagePreceded = 4;  { image descriptor preceeded by other unknown data }
  231.     geEmptyBlock = 5;                       { Block has no data }
  232.      geUnExpectedEOF = 6;  { unexpected EOF }
  233.     geBadCodeSize = 7;    { bad code size }
  234.     geBadCode = 8;                          { Bad code was found }
  235.     geBitSizeOverflow = 9; { bit size went beyond 12 bits }
  236.  
  237. implementation
  238.  
  239.  
  240. function Power(A, N: real): real;       { returns A raised to the power of N }
  241. begin
  242.     Power := exp(N * ln(A));
  243. end;
  244.  
  245.  
  246. { TGif }
  247. constructor TGif.Create;
  248. begin
  249.        {Create Memory Buffer to hold gif}
  250.         Stream := TMemoryStream.Create;
  251.         ImageLines := TList.Create;
  252.         ProgFlag := false;
  253. end;
  254.  
  255.  
  256. destructor TGif.Destroy;
  257. begin
  258.     if Stream <> nil then
  259.         Dispose(Stream);
  260. end;
  261.  
  262. procedure TGif.SetIndicators(MyGauge :TGauge; MyStat : TPanel);
  263. begin
  264.      ProgFlag := true;
  265.      Gauge := MyGauge;
  266.      Stat := MyStat;
  267. end;
  268.  
  269. function TGif.Convert(AGifName, ABmpName:string):integer;
  270. var
  271.    nRet   : integer;
  272. begin
  273.     
  274.     if Pos('.',AGifName) = 0 then     { if the filename has no extension add one }
  275.         AGifName := AGifName + '.gif';
  276.  
  277.      Stream.LoadFromFile(AGifName); {Load the file into memory}
  278.      nRet := GifConvert(ABmpName);
  279.                           
  280. end;   
  281.  
  282. function TGif.GifConvert(ABmpName:string) : integer;
  283. label Bottom;
  284. var
  285.    nRet : integer;
  286. begin
  287.      
  288.      nRet := 0;
  289.  
  290.      if ProgFlag then
  291.         Stat.Caption := 'Parsing Gif file...';
  292.  
  293.      {Parses the gif file already in memory}
  294.      nRet := ParseMem;
  295.      if (nRet<>0) then
  296.         goto Bottom;
  297.    
  298.      if ProgFlag then
  299.      begin
  300.         Gauge.MaxValue := (ImageDescriptor.ImageHeight*2)+10;
  301.         Gauge.Progress := 5;
  302.         Stat.Caption := 'Creating Bitmap header...';
  303.      end;
  304.  
  305.      {Create the bitmap header info}
  306.  
  307.      nRet := CreateBitHeader;
  308.      if (nRet<>0) then
  309.         goto Bottom;
  310.                     
  311.      if ProgFlag then
  312.      begin
  313.         Gauge.Progress := 10;
  314.         Stat.Caption := 'Decoding Gif...';
  315.      end;
  316.  
  317.      {Decode the gif.}
  318.      try 
  319.          Decode(TRUE);
  320.          except on EGPFault do 
  321.          begin
  322.               nRet := geNotGif;
  323.          end;
  324.      end;
  325.      
  326.      if (nRet <> 0) then
  327.           Goto Bottom;
  328.      
  329.      if ProgFlag then
  330.           Stat.Caption := 'Writing '+ABmpName+'...';
  331.      WriteBitmap(ABmpName);
  332.  
  333. Bottom:
  334.     GifConvert := nRet;
  335. end;
  336.  
  337.  
  338. function TGif.ConvertfromMem(AMemStream:TMemoryStream;ABmpName:string):integer;
  339. var
  340.    nRet :  integer;
  341. begin
  342.      if ProgFlag then
  343.         Stat.Caption := 'Loading Gif file...';
  344.      Stream.LoadFromStream(AMemStream);
  345.      GifConvert(ABmpName);
  346. end;
  347.  
  348.  
  349.       
  350. procedure TGif.Error(What: integer);
  351. begin
  352.     Status := What;
  353. end;
  354.  
  355.  
  356. {Decodes the header and palete info}
  357. function TGif.ParseMem : integer;
  358. label Bottom;
  359. begin
  360.     Stream.Read(Header, sizeof(Header)); { read the header }
  361.  
  362.     {Stupid validation tricks}
  363.     if Header.Signature <> 'GIF' then 
  364.    begin
  365.       ParseMem :=geNotGif;   { is vaild signature }
  366.       goto Bottom;
  367.    end;
  368.  
  369.     {Decode the header information}
  370.     Stream.Read(LogicalScreen, sizeof(LogicalScreen));
  371.  
  372.     if LogicalScreen.PackedFields and lsdGlobalColorTable = lsdGlobalColorTable then
  373.     begin
  374.         TableSize := trunc(Power(2,(LogicalScreen.PackedFields and lsdColorTableSize)+1));
  375.         Stream.Read(GlobalColorTable, TableSize*sizeof(TColorItem)); { read Global Color Table }
  376.     end
  377.     else
  378.    begin
  379.         ParseMem := geNoGlobalColor;
  380.       goto Bottom;
  381.    end;
  382.     {Done with Global Headers}
  383.  
  384.     {Image specific headers}
  385.     Stream.Read(ImageDescriptor, sizeof(ImageDescriptor)); { read image descriptor }
  386.  
  387.     {Decode image header info}
  388.     if ImageDescriptor.Seperator <> ImageSeperator then                     { verify that it is the descriptor }
  389.    begin
  390.         ParseMem := geImagePreceded;
  391.       goto Bottom;
  392.    end;
  393.  
  394.     {Check for local color table}
  395.     if ImageDescriptor.PackedFields and idLocalColorTable = idLocalColorTable then
  396.     begin                                                               { if local color table }
  397.         TableSize := trunc(Power(2,(ImageDescriptor.PackedFields and idColorTableSize)+1));
  398.         Stream.Read(LocalColorTable, TableSize*sizeof(TColorItem)); { read Local Color Table }
  399.         UseLocalColors := True;
  400.     end
  401.     else
  402.         UseLocalColors := false;
  403.  
  404.     {Check for interlaced}
  405.     if ImageDescriptor.PackedFields and idInterlaced = idInterlaced then
  406.     begin
  407.         Interlaced := true;
  408.         InterlacePass := 0;
  409.     end;
  410.     {End of image header stuff}
  411.  
  412.     {Reset then Expand capacity of the Image Lines list}
  413.     ImageLines.Clear;
  414.     {Note if you ever find a gif more than 16k pixels tall this will puke}
  415.     ImageLines.Capacity := ImageDescriptor.ImageHeight;
  416.  
  417.     if (Stream = nil) then{ check for stream error }
  418.    begin
  419.         ParseMem := geNoFile;
  420.       goto Bottom;
  421.    end;
  422.     
  423.     ParseMem := 0;
  424. Bottom:
  425. end;
  426.  
  427. procedure TGif.InitCompressionStream;
  428. var
  429.     I: integer;
  430. begin
  431.     {InitGraphics;}                           { Initialize the graphics display }
  432.     Stream.Read(LZWCodeSize, sizeof(byte));{ get minimum code size }
  433.     if not (LZWCodeSize in [2..9]) then     { valid code sizes 2-9 bits }
  434.         Error(geBadCodeSize);
  435.  
  436.     CurrCodeSize := succ(LZWCodeSize); { set the initial code size }
  437.     ClearCode := 1 shl LZWCodeSize;    { set the clear code }
  438.     EndingCode := succ(ClearCode);     { set the ending code }
  439.     HighCode := pred(ClearCode);                     { set the highest code not needing decoding }
  440.     BytesLeft := 0;                    { clear other variables }
  441.     BitsLeft := 0;
  442.     CurrentX := 0;
  443.     CurrentY := 0;
  444. end;
  445.  
  446. procedure TGif.ReadSubBlock;
  447. begin
  448.     Stream.Read(ImageData.Size, sizeof(ImageData.Size)); { get the data block size }
  449.     if ImageData.Size = 0 then Error(geEmptyBlock); { check for empty block }
  450.     Stream.Read(ImageData.Data, ImageData.Size);   { read in the block }
  451.     NextByte := 1;                                  { reset next byte }
  452.     BytesLeft := ImageData.Size;                                                                            { reset bytes left }
  453. end;
  454.  
  455. const
  456.     CodeMask: array[0..12] of longint = (  { bit masks for use with Next code }
  457.         0,
  458.         $0001, $0003,
  459.         $0007, $000F,
  460.         $001F, $003F,
  461.         $007F, $00FF,
  462.         $01FF, $03FF,
  463.         $07FF, $0FFF);
  464.  
  465. function TGif.NextCode: word; { returns a code of the proper bit size }
  466. var
  467.     Ret: longint;                           { temporary return value }
  468. begin
  469.     if BitsLeft = 0 then                                                                            { any bits left in byte ? }
  470.     begin                                   { any bytes left }
  471.         if BytesLeft <= 0 then                                                          { if not get another block }
  472.             ReadSubBlock;
  473.         CurrByte := ImageData.Data[NextByte]; { get a byte }
  474.         inc(NextByte);                        { set the next byte index }
  475.         BitsLeft := 8;                        { set bits left in the byte }
  476.         dec(BytesLeft);                       { decrement the bytes left counter }
  477.     end;
  478.     ret := CurrByte shr (8 - BitsLeft);                     { shift off any previosly used bits}
  479.     while CurrCodeSize > BitsLeft do        { need more bits ? }
  480.     begin
  481.         if BytesLeft <= 0 then                                                          { any bytes left in block ? }
  482.             ReadSubBlock;                       { if not read in another block }
  483.         CurrByte := ImageData.Data[NextByte]; { get another byte }
  484.         inc(NextByte);                        { increment NextByte counter }
  485.         ret := ret or (CurrByte shl BitsLeft);{ add the remaining bits to the return value }
  486.         BitsLeft := BitsLeft + 8;                                               { set bit counter }
  487.         dec(BytesLeft);                     { decrement bytesleft counter }
  488.     end;
  489.     BitsLeft := BitsLeft - CurrCodeSize;  { subtract the code size from bitsleft }
  490.     ret := ret and CodeMask[CurrCodeSize];{ mask off the right number of bits }
  491.     NextCode := ret;
  492. end;
  493.  
  494. { this procedure initializes the graphics mode and actually decodes the
  495.     GIF image }
  496. procedure TGif.Decode(Beep: boolean);
  497. var
  498.     SP: integer; { index to the decode stack }
  499.  
  500. { local procedure that decodes a code and puts it on the decode stack }
  501. procedure DecodeCode(var Code: word);
  502. begin
  503.     while Code > HighCode do { rip thru the prefix list placing suffixes }
  504.     begin                    { onto the decode stack }
  505.         DecodeStack[SP] := Suffix[Code]; { put the suffix on the decode stack }
  506.         inc(SP);                         { increment decode stack index }
  507.         Code := Prefix[Code];            { get the new prefix }
  508.     end;
  509.     DecodeStack[SP] := Code;        { put the last code onto the decode stack }
  510.     inc(SP);                                                                        { increment the decode stack index }
  511. end;
  512.  
  513. var
  514.     TempOldCode, OldCode: word;
  515.     BufCnt: word;           { line buffer counter }
  516.     Code, C: word;
  517.     CurrBuf: word;  { line buffer index }
  518. begin
  519.     InitCompressionStream;    { Initialize decoding paramaters }
  520.     OldCode := 0;
  521.     SP := 0;
  522.     BufCnt := ImageDescriptor.ImageWidth; { set the Image Width }
  523.     CurrBuf := 0;
  524.  
  525.     C := NextCode;                                          { get the initial code - should be a clear code }
  526.     while C <> EndingCode do  { main loop until ending code is found }
  527.     begin
  528.         if C = ClearCode then   { code is a clear code - so clear }
  529.         begin
  530.             CurrCodeSize := LZWCodeSize + 1;{ reset the code size }
  531.             Slot := EndingCode + 1;                                 { set slot for next new code }
  532.             TopSlot := 1 shl CurrCodeSize;  { set max slot number }
  533.             while C = ClearCode do
  534.                 C := NextCode;                  { read until all clear codes gone - shouldn't happen }
  535.             if C = EndingCode then
  536.             begin
  537.                 Error(geBadCode);   { ending code after a clear code }
  538.                 break;                                                  { this also should never happen }
  539.             end;
  540.             if C >= Slot { if the code is beyond preset codes then set to zero }
  541.                 then c := 0;
  542.             OldCode := C;
  543.             DecodeStack[sp] := C;                                   { output code to decoded stack }
  544.             inc(SP);                                               { increment decode stack index }
  545.         end
  546.         else   { the code is not a clear code or an ending code so it must }
  547.         begin  { be a code code - so decode the code }
  548.             Code := C;
  549.             if Code < Slot then     { is the code in the table? }
  550.             begin
  551.                 DecodeCode(Code);                                       { decode the code }
  552.                 if Slot <= TopSlot then
  553.                 begin                                { add the new code to the table }
  554.                     Suffix[Slot] := Code;                   { make the suffix }
  555.                     PreFix[slot] := OldCode;        { the previous code - a link to the data }
  556.                     inc(Slot);                                                              { increment slot number }
  557.                     OldCode := C;                                                   { set oldcode }
  558.                 end;
  559.                 if Slot >= TopSlot then { have reached the top slot for bit size }
  560.                 begin                   { increment code bit size }
  561.                     if CurrCodeSize < 12 then { new bit size not too big? }
  562.                     begin
  563.                         TopSlot := TopSlot shl 1;       { new top slot }
  564.                         inc(CurrCodeSize)                                       { new code size }
  565.                     end
  566.                     else
  567.                         Error(geBitSizeOverflow); { encoder made a boo boo }
  568.                 end;
  569.             end
  570.             else
  571.             begin           { the code is not in the table }
  572.                 if Code <> Slot then                    { code is not the next available slot }
  573.                     Error(geBadCode);  { so error out }
  574.  
  575.                 { the code does not exist so make a new entry in the code table
  576.                  and then translate the new code }
  577.                 TempOldCode := OldCode;  { make a copy of the old code }
  578.                 while OldCode > HighCode do { translate the old code and place it }
  579.                 begin                                   { on the decode stack }
  580.                     DecodeStack[SP] := Suffix[OldCode]; { do the suffix }
  581.                     OldCode := Prefix[OldCode];         { get next prefix }
  582.                 end;
  583.                 DecodeStack[SP] := OldCode;     { put the code onto the decode stack }
  584.                                                                         { but DO NOT increment stack index }
  585.                 { the decode stack is not incremented because because we are only
  586.                     translating the oldcode to get the first character }
  587.                 if Slot <= TopSlot then
  588.                 begin                 { make new code entry }
  589.                     Suffix[Slot] := OldCode;                 { first char of old code }
  590.                     Prefix[Slot] := TempOldCode; { link to the old code prefix }
  591.                     inc(Slot);                   { increment slot }
  592.                 end;
  593.                 if Slot >= TopSlot then { slot is too big }
  594.                 begin                   { increment code size }
  595.                     if CurrCodeSize < 12 then
  596.                     begin
  597.                         TopSlot := TopSlot shl 1;       { new top slot }
  598.                         inc(CurrCodeSize)                                       { new code size }
  599.                     end
  600.                     else
  601.                         Error(geBitSizeOverFlow);
  602.                 end;
  603.                 DecodeCode(Code); { now that the table entry exists decode it }
  604.                 OldCode := C;     { set the new old code }
  605.             end;
  606.         end;
  607.         { the decoded string is on the decode stack so pop it off and put it
  608.          into the line buffer }
  609.         while SP > 0 do
  610.         begin
  611.             dec(SP);
  612.             LineBuffer[CurrBuf] := DecodeStack[SP];
  613.             inc(CurrBuf);
  614.             dec(BufCnt);
  615.             if BufCnt = 0 then  { is the line full ? }
  616.             begin
  617.                 CreateLine;
  618.                 CurrBuf := 0;
  619.                 BufCnt := ImageDescriptor.ImageWidth;
  620.             end;
  621.         end;
  622.     C := NextCode;  { get the next code and go at is some more }
  623.     end;            { now that wasn't all that bad was it? }
  624. end;
  625.  
  626. function TGif.CreateBitHeader:integer;
  627. { This routine takes the values from the gif image
  628.   descriptor and fills in the appropriate values in the 
  629.   bit map header struct.
  630. }
  631. begin
  632.     BmHeader.biSize := Sizeof(TBitmapInfoHeader); 
  633.     BmHeader.biWidth := ImageDescriptor.ImageWidth; 
  634.     BmHeader.biHeight := ImageDescriptor.ImageHeight;
  635.     BmHeader.biPlanes := 1; {Arcane and rarely used}
  636.     BmHeader.biBitCount := 8; {Hmmm Should this be hardcoded ?}
  637.     BmHeader.biCompression := BI_RGB; {Sorry Did not implement compression in this version}
  638.     BmHeader.biSizeImage := 0; {Valid since we are not compressing the image}
  639.     BmHeader.biXPelsPerMeter :=143; {Rarely used very arcane field}
  640.     BmHeader.biYPelsPerMeter :=143; {Ditto}
  641.     BmHeader.biClrUsed := 0; {all colors are used}
  642.     BmHeader.biClrImportant := 0; {all colors are important}
  643.    CreateBitHeader := 0;
  644. end;
  645.  
  646. {fills in Line list with current line}
  647. procedure TGif.CreateLine;
  648. var
  649.     I: integer;
  650.    p: PBmLine;
  651.    prog: integer;
  652. begin
  653.  
  654.    Application.ProcessMessages;
  655.    {Create a new bmp line}
  656.    New(p);
  657.  
  658.    {Fill in the data}
  659.    p^.LineData := LineBuffer;
  660.    p^.LineNo := CurrentY;
  661.    if ProgFlag then
  662.    begin
  663.        prog := Gauge.Progress + 1;
  664.        Gauge.Progress:=prog;
  665.    end;
  666.    {Add it to the list of lines}
  667.    ImageLines.Add(p); 
  668.  
  669.    {Prepare for the next line}
  670.     inc(CurrentY);
  671.  
  672.     if InterLaced then     { Interlace support }
  673.     begin
  674.         case InterlacePass of
  675.             0: CurrentY := CurrentY + 7;
  676.             1: CurrentY := CurrentY + 7;
  677.             2: CurrentY := CurrentY + 3;
  678.             3: CurrentY := CurrentY + 1;
  679.         end;
  680.  
  681.         if CurrentY >= ImageDescriptor.ImageHeight then
  682.         begin
  683.             inc(InterLacePass);
  684.             case InterLacePass of
  685.                 1: CurrentY := 4;
  686.                 2: CurrentY := 2;
  687.                 3: CurrentY := 1;
  688.             end;
  689.         end;
  690.     end;
  691. end;
  692.  
  693. procedure TGif.WriteBitmap(ABMPName:string);
  694. var
  695. mp:TMemoryStream;
  696. fp:TFileStream;
  697. BitFile: TBitmapFileHeader;
  698. i:integer;
  699. Line:integer;
  700. ch:char;
  701. p:PBmLine;
  702. prog : integer;
  703. begin
  704.  
  705. BitFile.bfSize := (3*255) + {Color map info}
  706.                   sizeof(TBitmapFileHeader) +  
  707.                   sizeof(TBitmapInfoHeader) +
  708.                   (ImageDescriptor.ImageHeight*ImageDescriptor.ImageWidth);
  709.  
  710. BitFile.bfReserved1 := 0; {not currently used}
  711. BitFile.bfReserved2 := 0; {not currently used}
  712. BitFile.bfOffBits := (4*256)+
  713.                      sizeof(TBitmapFileHeader)+
  714.                      sizeof(TBitmapInfoHeader);
  715.  
  716. {Create a memory stream to build the bm into}
  717. mp := TMemoryStream.Create;
  718.  
  719. {Write the file header}
  720. ch:='B';
  721. mp.Write(ch,1);
  722. ch:='M';
  723. mp.Write(ch,1);
  724. mp.Write(BitFile.bfSize,sizeof(BitFile.bfSize));
  725. mp.Write(BitFile.bfReserved1,sizeof(BitFile.bfReserved1));
  726. mp.Write(BitFile.bfReserved2,sizeof(BitFile.bfReserved2));
  727. mp.Write(BitFile.bfOffBits,sizeof(BitFile.bfOffBits));
  728.  
  729. {Write the bitmap image header info}
  730. mp.Write(BmHeader,sizeof(BmHeader));
  731.  
  732. {if false then
  733. begin}
  734.     {Write the BGR palete inforamtion to this file}
  735.     if UseLocalColors then {Use the local color table}
  736.     begin
  737.          for i:=0 to 255 do
  738.          begin  
  739.                 mp.Write(LocalColorTable[i].Blue,1);
  740.                 mp.Write(LocalColorTable[i].Green,1);
  741.                 mp.Write(LocalColorTable[i].Red,1);
  742.                 mp.Write(ch,1); {Bogus palete entry required by windows}
  743.          end;
  744.     end
  745.     else {Use the global table}
  746.     begin
  747.          for i:=0 to 255 do
  748.          begin  
  749.                 mp.Write(GlobalColorTable[i].Blue,1);
  750.                 mp.Write(GlobalColorTable[i].Green,1);
  751.                 mp.Write(GlobalColorTable[i].Red,1);
  752.                 mp.Write(ch,1); {Bogus palete entry required by windows}
  753.          end;                                               
  754.     end;
  755. {end;}
  756.  
  757. {Init the Line Counter}
  758. Line := ImageDescriptor.ImageHeight;
  759. {Write out File lines in reverse order}
  760. while Line >= 0 do
  761. begin
  762.     {Go through the line list in reverse order looking for the
  763.     current Line. Use reverse order since non interlaced gifs are 
  764.     stored top to bottom.  Bmp file need to be written bottom to 
  765.     top}
  766.     for i:= (ImageLines.Count-1) downto 0  do
  767.     begin
  768.         if ProgFlag then
  769.         begin
  770.             prog := Gauge.Progress + 1;
  771.             Gauge.Progress:=prog;
  772.         end;
  773.          p := ImageLines.Items[i];
  774.          if p^.LineNo = Line then
  775.          begin
  776.               mp.Write(p^.LineData,ImageDescriptor.ImageWidth);
  777.               break;
  778.          end;
  779.     end;
  780.     dec(Line);
  781. end;
  782.  
  783. mp.SaveToFile(ABMPName);
  784. mp.Free;
  785. end;
  786.  
  787. end.
  788.